import { showErrorMessage } from "@ap/util/vscode/message";
import getFilePath from "@ap/util/vscode/getFilePath";
import { PackageConfig } from "@ap/types/config";
import { read, ReadMode, writeFile } from "./fs";
import { parseJSON, tryRun } from "./data";

import path from "path";
const BASE_KEY = "ArenaPro";
export const BASE_CFG_JSON = "dao3.config.json";

/**
 * 检查给定的键是否合法。
 * @param key 要检查的键。
 */
function checkKeyValidity(key: string): boolean {
  return typeof key === "string" && key.trim() !== "";
}

/**
 * 封装的文件读取和JSON解析函数。
 * @param filePath 文件路径。
 * @returns 解析后的JSON对象，如果失败返回失败原因。
 */
async function readJsonFile(
  filePath: string,
): Promise<Record<string, any> | Error> {
  try {
    const { READ, CREATE } = ReadMode;
    const fileContent = (await read(filePath, { mode: READ }))?.toString();

    if (typeof fileContent !== "string" && !fileContent) {
      return new Error();
    }

    const parsed = await parseJSON<Record<string, any>, Error>(
      fileContent,
      new Error("JSON解析失败"),
    );
    if (parsed instanceof Error) {
      throw parsed;
    }

    return parsed as Record<string, any>;
  } catch (err) {
    return err as Error;
  }
}

async function writeTo(
  filePath: string,
  content: Record<string, any>,
): Promise<Error | void> {
  try {
    return await writeFile(filePath, JSON.stringify(content, null, 4));
  } catch (err) {
    return err as Error;
  }
}

/**
 * 读取 dao3.config.json 文件中的 ArenaPro 键下的配置。
 * @returns 返回一个 Promise，表示读取 dao3.config.json 文件中的 ArenaPro 键下的配置。
 *
 * 已包装键
 */
async function loadPackageJson(): Promise<null | PackageConfig> {
  let filePath: string | undefined;
  let fileContent: Record<string, any> | Error;

  filePath = getFilePath();
  if (!filePath) {
    return null;
  }
  fileContent = await readJsonFile(path.join(filePath, BASE_CFG_JSON));

  const fileJson = fileContent as Record<string, any>;
  return {
    ...fileJson[BASE_KEY],
  };
}

/**
 * 写入 dao3.config.json 文件中的 ArenaPro 键下的配置。
 * @param content 要写入的配置。
 * @returns 返回一个 Promise，表示写入 dao3.config.json 文件中的 ArenaPro 键下的配置。
 *
 * 已包装键
 */
async function writePackageJson(content: PackageConfig): Promise<Error | void> {
  const filePath = getFilePath(BASE_CFG_JSON);
  if (!filePath) {
    return;
  }

  const fileContent = await readJsonFile(filePath);
  if (fileContent instanceof Error) {
    showErrorMessage(
      "读取 dao3.config.json 时发生错误: " + fileContent.message,
    );
    return;
  }

  const updatedContent = {
    ...fileContent,
    [BASE_KEY]: content,
  };
  const wrote = await writeTo(filePath, updatedContent);
  if (wrote instanceof Error) {
    showErrorMessage("写回 dao3.config.json 时发生错误: " + wrote.message);
    return;
  }
}

/**
 * 更新 dao3.config.json 文件中ArenaPro键下的特定属性。
 * @param key 要更新的属性键。
 * @param value 要更新的属性值。
 * @returns 返回一个 Promise，表示文件更新操作是否成功。
 */
export async function updatePackageJson(
  key: string,
  value: any,
): Promise<string | null> {
  if (!checkKeyValidity(key)) {
    showErrorMessage("键名需是字符串类型");
    return null;
  }
  const packageJson = await loadPackageJson();
  if (!packageJson) {
    return null;
  }

  packageJson[key] = value;
  await writePackageJson(packageJson);
  return getFilePath(BASE_CFG_JSON)!;
}

/**
 * 读取 dao3.config.json 文件中ArenaPro键下的特定属性。
 * @param key 要更新的属性键。
 * @returns 返回一个 Promise，表示key的值。
 */
export async function getPackageJson<T = any>(key: string): Promise<T | void> {
  if (!checkKeyValidity(key)) {
    showErrorMessage("键名需是字符串类型");
    return;
  }
  const packageJson = await loadPackageJson();
  if (!packageJson) {
    return;
  }

  return packageJson[key];
}
